﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace Pfz.Collections
{
	/// <summary>
	/// Enumerable collection that only holds the last value.
	/// This is useful if you have many clients which different speeds to the same
	/// data (like video) and you know the last data is complete (so you can skip 
	/// frames). The slower clients will lose many frames, while the fastest ones
	/// can get all the frames.
	/// This class is completely thread-safe.
	/// </summary>
	/// <typeparam name="T">The type of the data this "collection" holds.</typeparam>
	public sealed class ActualValueCollection<T>:
		IAdvancedDisposable,
		IEnumerable<T>,
		IFastEnumerable<T>
	where
		T: class
	{
		internal readonly object _lock = new object();
		
		/// <summary>
		/// Stops this collection and releases any enumerator waiting on it.
		/// </summary>
		public void Dispose()
		{
			lock(_lock)
			{
				_wasDisposed = true;
				_value = null;
				
				Monitor.PulseAll(_lock);
			}
		}
		
		private bool _wasDisposed;
		/// <summary>
		/// Gets a value indicating if this collection was disposed.
		/// </summary>
		public bool WasDisposed
		{
			get
			{
				return _wasDisposed;
			}
		}
	
		private T _value;
		/// <summary>
		/// Gets or sets the current value. When setting the value, any
		/// waiting enumerators will receive it as the next value.
		/// </summary>
		public T Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");
			
				lock(_lock)
				{
					if (_wasDisposed)
						throw new ObjectDisposedException(GetType().FullName);
						
					_value = value;
					
					Monitor.PulseAll(_lock);
				}
			}
		}
		
		/// <summary>
		/// Gets an enumerator that receives only the most up to date values.
		/// </summary>
		public ActualValueEnumerator<T> GetEnumerator()
		{
			return new ActualValueEnumerator<T>(this);
		}

		#region IEnumerable<T> Membres
			IEnumerator<T> IEnumerable<T>.GetEnumerator()
			{
				return GetEnumerator();
			}
		#endregion
		#region IEnumerable Membres
			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		#endregion
		#region IFastEnumerable<T> Members
			IFastEnumerator<T> IFastEnumerable<T>.GetEnumerator()
			{
				return GetEnumerator();
			}
		#endregion
	}
}
